using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using FarseerPhysics;
using FarseerPhysics.Dynamics;
using TomShane.Neoforce.Controls;
using InputHandlers.Mouse;

namespace CaptialVices
{
    public class CaptialVices : Game
    {
        AnimatedSprite animSprite;
        AnimatedSprite animSprite2;
        AnimatedSprite playerSprite;
        AnimatedSprite greaseSprite;

        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        //Neoforce Manager
        Manager manager;

        public static Dictionary<String, Texture2D> skillImages;
        public static Dictionary<String, AnimatedSprite> blockImages;

        public static Camera camera;

        List<Level> levels;

        Player player;
        World world;

        SkillBar skillBar;
        CurrentPowerDisplay currentPowerDisplay;

        LevelEditor editor;
        Window editorWindow;

        Level testLevel;

        public CaptialVices()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferWidth = 1280;
            graphics.PreferredBackBufferHeight = 720;
            Content.RootDirectory = "Content";

            MouseHandler.Instance.Reset();
        }

        protected override void Initialize()
        {
            //Show the cursor
            IsMouseVisible = true;
            // Create an instance of manager using Default skin. We set the fourth parameter to true,
            // so the instance of manager is registered as an XNA game component and methods
            // like Initialize(), Update() and Draw() are called automatically in the game loop.
            // If you set this parameter to false, you have to call Manager.Initialize(), 
            // Manager.Update() and Manager.Draw() manually in their respective overriden methods
            // of the game class.
            // If you use two-parameter constructor, Default skin is used and manager is registered.
            manager = new Manager(this, graphics, "Blue");
            manager.Initialize();
            base.Initialize(); 
        }

        private void CreateMenu()
        {
            LevelEditor levelEditor = new LevelEditor(manager);
            editorWindow = levelEditor.CreateLevelEditor();
        }

        void changeBlockHeight(object sender, TomShane.Neoforce.Controls.EventArgs e)
        {
            SpinBox spinBox = sender as SpinBox;
            testLevel.ChangeBlockHeightAtIndex(4, (int)double.Parse(spinBox.Text));
        }

        void changeBlockType(object sender, TomShane.Neoforce.Controls.EventArgs e)
        {
            ComboBox blockTypeCombo = sender as ComboBox;
            //testLevel.ChangeBlockTypeAtIndex(4, blockTypeCombo.Text, blockImages[blockTypeCombo.Text]);
        }

        private void LoadSkillImages()
        {
            skillImages = new Dictionary<string, Texture2D>();
            currentPowerDisplay = new CurrentPowerDisplay();

            Texture2D gluttonySkillTex = Content.Load<Texture2D>(Skills.GLUTONY);
            skillImages.Add(Skills.GLUTONY, gluttonySkillTex);

            Texture2D greedSkillTex = Content.Load<Texture2D>(Skills.GREED);
            skillImages.Add(Skills.GREED, greedSkillTex);

            Texture2D wrathSkillTex = Content.Load<Texture2D>(Skills.WRATH);
            skillImages.Add(Skills.WRATH, wrathSkillTex);

            Texture2D prideSkillTex = Content.Load<Texture2D>(Skills.PRIDE);
            skillImages.Add(Skills.PRIDE, prideSkillTex);

            Texture2D envySkillTex = Content.Load<Texture2D>(Skills.ENVY);
            skillImages.Add(Skills.ENVY, envySkillTex);

            Texture2D lustSkillTex = Content.Load<Texture2D>(Skills.LUST);
            skillImages.Add(Skills.LUST, lustSkillTex);

            Texture2D slothSkillTex = Content.Load<Texture2D>(Skills.SLOTH);
            skillImages.Add(Skills.SLOTH, slothSkillTex);

            
            //Set the skill images for the current power display
            currentPowerDisplay.SkillImages = skillImages;
        }

        private void SetUpCameraAndWorld()
        {
            // Create a camera instance and limit its moving range
            camera = new Camera(GraphicsDevice.Viewport) { Limits = new Rectangle(0, 0, 3200, 900) };

            // World is the most important farseer object. It's where
            // all the objects should be registered and it handles the 
            // entire simulation via the step function.
            // Here we instantiate it with earth like gravity
            world = new World(new Vector2(0, 9.8f));
        }

        private void LoadLandBlocks()
        {
            blockImages = new Dictionary<string, AnimatedSprite>();
            blockImages.Add(Blocks.GRASS_BLOCK_ONE, new AnimatedSprite(Content.Load<Texture2D>(Blocks.GRASS_BLOCK_ONE)));
            blockImages.Add(Blocks.GRASS_BLOCK_TWO, new AnimatedSprite(Content.Load<Texture2D>(Blocks.GRASS_BLOCK_TWO)));
            blockImages.Add(Blocks.GRASS_BLOCK_THREE, new AnimatedSprite(Content.Load<Texture2D>(Blocks.GRASS_BLOCK_THREE)));
        }

        private void SetUpSkillBar()
        {
            skillBar = new SkillBar();
            skillBar.SetIcons(skillImages, new Vector2(50, graphics.GraphicsDevice.Viewport.Height - 100));
        }

        private void LoadTestTerrain(Player player)
        {
            testLevel = new Level();
            testLevel.camera = camera;
            testLevel.world = world;
            testLevel.player = player;
            testLevel.skillBar = skillBar;
            testLevel.currentPowerDisplay = currentPowerDisplay;
            testLevel.layers = new List<Layer>
            {
                new Layer(camera) { Parallax = new Vector2(0.0f, 1.0f) },
                new Layer(camera) { Parallax = new Vector2(0.5f, 1.0f) },
                new Layer(camera) { Parallax = new Vector2(1.0f, 1.0f) }

            };

            // Add one sprite to each layer
            testLevel.layers[0].Sprites.Add(new Sprite { Texture = Content.Load<Texture2D>("Layer1") });
            testLevel.layers[1].Sprites.Add(new Sprite { Texture = Content.Load<Texture2D>("Layer2") });


            Random rand = new Random();

            int offsetX = 0;
            int offsetY = 0;

            for (int i = 0; i < 10; i++)
            {
                AnimatedSprite sprite = null;

                switch (rand.Next(3))
                {
                    case 0:
                        sprite = blockImages[Blocks.GRASS_BLOCK_ONE];
                        break;
                    case 1:
                        sprite = blockImages[Blocks.GRASS_BLOCK_TWO];
                        break;
                    case 2:
                        sprite = blockImages[Blocks.GRASS_BLOCK_THREE];
                        break;
                }

                offsetX += sprite.Width;
                offsetY = rand.Next(100);


                DrawablePhysicsObject floor = null;
                floor = new DrawablePhysicsObject(world, sprite, new Vector2(sprite.Width, sprite.Height), 1000);
                floor.Position = new Vector2(offsetX, GraphicsDevice.Viewport.Height - offsetY);
                floor.Body.BodyType = BodyType.Static;

                testLevel.layers[2].Sprites.Add(floor);
            }

            testLevel.layers[2].Sprites.Add(player);
        }
      
        private void SetUpPlayer()
        {
            playerSprite = new AnimatedSprite(Content.Load<Texture2D>("MCSpriteSheet"),
                                                new Dictionary<String, Rectangle[]>()
                                                {
                                                    {"Walk", new Rectangle[]{
                                                            new Rectangle(200, 0, 200, 300),
                                                            new Rectangle(400, 0, 200, 300),
                                                            new Rectangle(600, 0, 200, 300),
                                                            new Rectangle(800, 0, 200, 300),
                                                            new Rectangle(1000, 0, 200, 300),
                                                            new Rectangle(1200, 0, 200, 300),
                                                            new Rectangle(1400, 0, 200, 300),
                                                            new Rectangle(1600, 0, 200, 300),
                                                            new Rectangle(1800, 0, 200, 300),
                                                         }
                                                    },
                                                    {"Idle", new Rectangle[]{
                                                            new Rectangle(0, 0, 200, 300)
                                                        }
                                                    },
                                                    {"Jump", new Rectangle[]{
                                                            new Rectangle(2200, 0, 200, 300),
                                                            new Rectangle(2400, 0, 200, 300)
                                                        }
                                                    }
                                                });

            playerSprite.FrameTime = 0.1;
            playerSprite.scale = 0.4f;

           player = new Player
           (
              world,
              playerSprite,
              Content.Load<Texture2D>("Player"),
              Content.Load<Texture2D>("Wheel"),
              new Vector2(20, 75),
              150,
              new Vector2(430, 0)
          );
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            LoadSkillImages();

            SetUpCameraAndWorld();

            animSprite = new AnimatedSprite(Content.Load<Texture2D>("gruntSpriteSheet"),
                                            new Rectangle[]{
                                                new Rectangle(0, 0, 150, 150),
                                                new Rectangle(150, 0, 150, 150),
                                                new Rectangle(300, 0, 150, 150),
                                                new Rectangle(450, 0, 150, 150),
                                                new Rectangle(600, 0, 150, 150),
                                                new Rectangle(750, 0, 150, 150), 
                                                new Rectangle(900, 0, 150, 150),
                                                new Rectangle(1050, 0, 150, 150),
                                                new Rectangle(1200, 0, 150, 150)
                                            }
                                            );

            animSprite2 = new AnimatedSprite(Content.Load<Texture2D>("firspritesheet"),
                                            new Rectangle[]{
                                                new Rectangle(0, 0, 150, 150),
                                                new Rectangle(150, 0, 150, 150),
                                                new Rectangle(300, 0, 150, 150),
                                                new Rectangle(450, 0, 150, 150),
                                                new Rectangle(600, 0, 150, 150)
                                            });

            greaseSprite = new AnimatedSprite(Content.Load<Texture2D>(Blocks.GREASE),
                                            new Rectangle[]
                                            {
                                                new Rectangle(0, 0, 182, 49),
                                                new Rectangle(0, 50, 182, 49),
                                                new Rectangle(0, 99, 182, 49),
                                                new Rectangle(0, 148, 182, 49)
                                            });

            greaseSprite.FrameTime = 0.9;
            greaseSprite.scale = 3.0f;

            animSprite.FrameTime = 1.0;

            animSprite2.FrameTime = 1.0;

            LoadLandBlocks();

            SetUpSkillBar();

            SetUpPlayer();

            LoadTestTerrain(player);

            CreateMenu();
        }

        protected override void Update(GameTime gameTime)
        {
            MouseHandler.Instance.Poll(Mouse.GetState());

            testLevel.Update(gameTime);

            if (Keyboard.GetState().IsKeyDown(Keys.Enter))
            {
                Level.WriteLevelToFile(testLevel, "hi");
            }
            if (Keyboard.GetState().IsKeyDown(Keys.OemTilde))
            {
                editorWindow.Show();
            }

            manager.Update(gameTime);

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {

            manager.BeginDraw(gameTime);


            manager.Draw(gameTime);
            testLevel.Draw(spriteBatch, gameTime);        

            manager.EndDraw();

            
            base.Draw(gameTime);
        }
    }
}
